//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            xprimimpl.cpp - primitives implementation
// AUTHOR:          Vladimir Gumenuk
// DATE:            11-Dec-2012
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xprimimpl.h"

// x = -x;
int FASTCALL const_neg( XELEMENT x )
{
    switch( x.bType )
    {
    case t_s1: x._s1 = -x._s1; break;
    case t_u1: x._u1 = -x._u1; break; // should it generate warning for all unsigned types?
    case t_s2: x._s2 = -x._s2; break;
    case t_u2: x._u2 = -x._u2; break;
    case t_s4: x._s4 = -x._s4; break;
    case t_u4: x._u4 = -x._u4; break;
    case t_s8: x._s8 = -x._s8; break;
    case t_u8: x._u8 = -x._u8; break;
    case t_r4: x._r4 = -x._r4; break;
    case t_r8: x._r8 = -x._r8; break;
    case t_p : 
    default  :
        return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// x = ~x
int FASTCALL const_not( XELEMENT x )
{
    switch( x.bType )
    {
    case t_s1: x._s1 = ~x._s1; break;
    case t_u1: x._u1 = ~x._u1; break; // should it generate warning for all unsigned types? VS doesn't...
    case t_s2: x._s2 = ~x._s2; break;
    case t_u2: x._u2 = ~x._u2; break;
    case t_s4: x._s4 = ~x._s4; break;
    case t_u4: x._u4 = ~x._u4; break;
    case t_s8: x._s8 = ~x._s8; break;
    case t_u8: x._u8 = ~x._u8; break;
    case t_r4:
    case t_r8:
    case t_p : 
    default  :
        return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

int FASTCALL const_inc( XELEMENT x )
{
    switch( x.bType )
    {
    case t_s1: x._s1 += 1; break;
    case t_u1: x._u1 += 1; break;
    case t_s2: x._s2 += 1; break;
    case t_u2: x._u2 += 1; break;
    case t_s4: x._s4 += 1; break;
    case t_u4: x._u4 += 1; break;
    case t_s8: x._s8 += 1; break;
    case t_u8: x._u8 += 1; break;
    case t_r4: x._r4 += 1.0f; break;
    case t_r8: x._r8 += 1.0; break;
    case t_p : 
    default  :
        return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

int FASTCALL const_dec( XELEMENT x )
{
    switch( x.bType )
    {
    case t_s1: x._s1 -= 1; break;
    case t_u1: x._u1 -= 1; break;
    case t_s2: x._s2 -= 1; break;
    case t_u2: x._u2 -= 1; break;
    case t_s4: x._s4 -= 1; break;
    case t_u4: x._u4 -= 1; break;
    case t_s8: x._s8 -= 1; break;
    case t_u8: x._u8 -= 1; break;
    case t_r4: x._r4 -= 1.0f; break;
    case t_r8: x._r8 -= 1.0; break;
    case t_p : 
    default  :
        return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// nz.T        v1 ? -> 1/0
int FASTCALL const_nz( XELEMENT v1, XELEMENT vRes )
{
    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 != 0 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 != 0 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 != 0 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 != 0 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 != 0 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 != 0 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 != 0 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 != 0 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 != 0 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 != 0 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  != 0 ) ? 1 : 0; break;
    default  : return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// lor.T       v1, v2 || -> 1/0
int FASTCALL const_lor( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType == t_r4 || v1.bType == t_r8 || v2.bType == t_r4 || v2.bType == t_r8 ) {
        return ERR_INVALID_TYPE;
    }
    vRes.bType = t_s4;
    vRes.bAccess = usr_VarRW;
    vRes._s4 = ( v1._s8 || v2._s8 ) ? 1 : 0;
    return XORT_OK;
}

// land.T      v1, v2 && -> 1/0
int FASTCALL const_land( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType == t_r4 || v1.bType == t_r8 || v2.bType == t_r4 || v2.bType == t_r8 ) {
        return ERR_INVALID_TYPE;
    }
    vRes.bType = t_s4;
    vRes.bAccess = usr_VarRW;
    vRes._s4 = ( v1._s8 && v2._s8 ) ? 1 : 0;
    return XORT_OK;
}

// lnot.T      v = !v
int FASTCALL const_lnot( XELEMENT x )
{
    if( x.bType == t_r4 || x.bType == t_r8 ) {
        return ERR_INVALID_TYPE;
    }
    x.bType = t_s4;
    x.bAccess = usr_VarRW;
    x._s4 = ( x._s8 == 0 ) ? 1 : 0;
    return XORT_OK;
}

// cmpeq.T     v1, v2 == -> 1/0
int FASTCALL const_cmpeq( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 == v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 == v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 == v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 == v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 == v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 == v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 == v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 == v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 == v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 == v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  == v2._p  ) ? 1 : 0; break;
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// cmpneq.T    v1, v2 != -> 1/0
int FASTCALL const_cmpneq( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 != v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 != v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 != v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 != v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 != v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 != v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 != v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 != v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 != v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 != v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  != v2._p  ) ? 1 : 0; break;
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// cmpgt.T     v1, v2 >  -> 1/0
int FASTCALL const_cmpgt( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 > v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 > v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 > v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 > v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 > v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 > v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 > v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 > v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 > v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 > v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  > v2._p  ) ? 1 : 0; break; // hm, why not? :)
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// cmplt.T     v1, v2 <  -> 1/0
int FASTCALL const_cmplt( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 < v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 < v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 < v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 < v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 < v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 < v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 < v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 < v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 < v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 < v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  < v2._p  ) ? 1 : 0; break; // hm, why not? :)
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// cmpge.T     v1, v2 >= -> 1/0
int FASTCALL const_cmpge( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 >= v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 >= v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 >= v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 >= v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 >= v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 >= v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 >= v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 >= v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 >= v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 >= v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  >= v2._p  ) ? 1 : 0; break; // hm, why not? :)
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// cmple.T     v1, v2 <= -> 1/0
int FASTCALL const_cmple( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;

    vRes.bType   = t_s4;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s4 = ( v1._s1 <= v2._s1 ) ? 1 : 0; break;
    case t_u1: vRes._s4 = ( v1._u1 <= v2._u1 ) ? 1 : 0; break;
    case t_s2: vRes._s4 = ( v1._s2 <= v2._s2 ) ? 1 : 0; break;
    case t_u2: vRes._s4 = ( v1._u2 <= v2._u2 ) ? 1 : 0; break;
    case t_s4: vRes._s4 = ( v1._s4 <= v2._s4 ) ? 1 : 0; break;
    case t_u4: vRes._s4 = ( v1._u4 <= v2._u4 ) ? 1 : 0; break;
    case t_s8: vRes._s4 = ( v1._s8 <= v2._s8 ) ? 1 : 0; break;
    case t_u8: vRes._s4 = ( v1._u8 <= v2._u8 ) ? 1 : 0; break;
    case t_r4: vRes._s4 = ( v1._r4 <= v2._r4 ) ? 1 : 0; break;
    case t_r8: vRes._s4 = ( v1._r8 <= v2._r8 ) ? 1 : 0; break;
    case t_p : vRes._s4 = ( v1._p  <= v2._p  ) ? 1 : 0; break; // hm, why not? :)
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// ifz         v1 ? -> ...
int FASTCALL const_ifz( XELEMENT x, int& iResult )
{
    switch( x.bType )
    {
    case t_s1: iResult = ( x._s1 == 0 ) ? 1 : 0; break;
    case t_u1: iResult = ( x._u1 == 0 ) ? 1 : 0; break;
    case t_s2: iResult = ( x._s2 == 0 ) ? 1 : 0; break;
    case t_u2: iResult = ( x._u2 == 0 ) ? 1 : 0; break;
    case t_s4: iResult = ( x._s4 == 0 ) ? 1 : 0; break;
    case t_u4: iResult = ( x._u4 == 0 ) ? 1 : 0; break;
    case t_s8: iResult = ( x._s8 == 0 ) ? 1 : 0; break;
    case t_u8: iResult = ( x._u8 == 0 ) ? 1 : 0; break;
    case t_r4: iResult = ( x._r4 == 0.0f ) ? 1 : 0; break;
    case t_r8: iResult = ( x._r8 == 0.0 ) ? 1 : 0; break;
    case t_p : iResult = ( x._p  == 0 ) ? 1 : 0; break;
    default  : return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

// ifnz        v1 != 0 -> ...
int FASTCALL const_ifnz( XELEMENT x, int& iResult )
{
    switch( x.bType )
    {
    case t_s1: iResult = ( x._s1 != 0 ) ? 1 : 0; break;
    case t_u1: iResult = ( x._u1 != 0 ) ? 1 : 0; break;
    case t_s2: iResult = ( x._s2 != 0 ) ? 1 : 0; break;
    case t_u2: iResult = ( x._u2 != 0 ) ? 1 : 0; break;
    case t_s4: iResult = ( x._s4 != 0 ) ? 1 : 0; break;
    case t_u4: iResult = ( x._u4 != 0 ) ? 1 : 0; break;
    case t_s8: iResult = ( x._s8 != 0 ) ? 1 : 0; break;
    case t_u8: iResult = ( x._u8 != 0 ) ? 1 : 0; break;
    case t_r4: iResult = ( x._r4 != 0.0f ) ? 1 : 0; break;
    case t_r8: iResult = ( x._r8 != 0.0 ) ? 1 : 0; break;
    case t_p : iResult = ( x._p  != 0 ) ? 1 : 0; break;
    default  : return ERR_INVALID_TYPE;
    }
    return XORT_OK;
}

int FASTCALL arith_or( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 | v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 | v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 | v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 | v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 | v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 | v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 | v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 | v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_xor( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 ^ v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 ^ v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 ^ v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 ^ v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 ^ v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 ^ v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 ^ v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 ^ v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_and( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 & v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 & v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 & v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 & v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 & v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 & v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 & v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 & v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_shl( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 << v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 << v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 << v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 << v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 << v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 << v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 << v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 << v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_shr( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 >> v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 >> v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 >> v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 >> v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 >> v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 >> v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 >> v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 >> v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_add( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 + v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 + v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 + v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 + v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 + v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 + v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 + v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 + v2._u8; break;
    case t_r4: vRes._r4 = v1._r4 + v2._r4; break;
    case t_r8: vRes._r8 = v1._r8 + v2._r8; break;
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_sub( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 - v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 - v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 - v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 - v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 - v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 - v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 - v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 - v2._u8; break;
    case t_r4: vRes._r4 = v1._r4 - v2._r4; break;
    case t_r8: vRes._r8 = v1._r8 - v2._r8; break;
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_mul( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 * v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 * v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 * v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 * v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 * v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 * v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 * v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 * v2._u8; break;
    case t_r4: vRes._r4 = v1._r4 * v2._r4; break;
    case t_r8: vRes._r8 = v1._r8 * v2._r8; break;
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_div( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 / v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 / v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 / v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 / v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 / v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 / v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 / v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 / v2._u8; break;
    case t_r4: vRes._r4 = v1._r4 / v2._r4; break;
    case t_r8: vRes._r8 = v1._r8 / v2._r8; break;
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}

int FASTCALL arith_mod( XELEMENT v1, XELEMENT v2, XELEMENT vRes )
{
    if( v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    vRes.bType   = v1.bType;
    vRes.bAccess = usr_VarRW;

    switch( v1.bType )
    {
    case t_s1: vRes._s1 = v1._s1 % v2._s1; break;
    case t_u1: vRes._u1 = v1._u1 % v2._u1; break;
    case t_s2: vRes._s2 = v1._s2 % v2._s2; break;
    case t_u2: vRes._u2 = v1._u2 % v2._u2; break;
    case t_s4: vRes._s4 = v1._s4 % v2._s4; break;
    case t_u4: vRes._u4 = v1._u4 % v2._u4; break;
    case t_s8: vRes._s8 = v1._s8 % v2._s8; break;
    case t_u8: vRes._u8 = v1._u8 % v2._u8; break;
    case t_r4: 
    case t_r8: 
    case t_p : 
    default: return ERR_INVALID_TYPE;
    }
    return XORT_OK;    
}
